home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 June / Macworld (1999-06).dmg / Shareware World / Info / For Developers / MacZoop2.0.sea / MacZoop2.0 / Required Classes / ZArray.cpp < prev    next >
Text File  |  1999-01-27  |  19KB  |  728 lines

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            MacZoop - "the framework for the rest of us"         
  5. *
  6. *
  7. *
  8. *            ZArray.cpp            -- the basic container class object
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21.  
  22. #include    "ZArray.h"
  23. #include    "MacZoop.h"
  24.  
  25. #include    <stdlib.h>
  26.  
  27. static short    vCompareFunc( void* a, void* b, const long ref = 0 );
  28.  
  29.  
  30. CLASSCONSTRUCTOR( ZArray );
  31.  
  32. /*-------------------------------***  CONSTRUCTOR  ***----------------------------------*/
  33.  
  34.  
  35. ZArray::ZArray( short elementSize )
  36.     : ZComrade()
  37. {
  38.     classID = CLASS_ZArray;
  39.     
  40.     blkSize = elementSize;
  41.     numElements = 0;
  42.     physicalBlks = kNumPhysicalBlockAlloc;
  43.     
  44.     FailNIL( a = NewHandle( elementSize * physicalBlks ));
  45. }
  46.  
  47.  
  48. /*--------------------------------***  DESTRUCTOR  ***----------------------------------*/
  49.  
  50. ZArray::~ZArray()
  51. {
  52.     if (a)
  53.         DisposeHandle( a );
  54. }
  55.  
  56.  
  57. /*--------------------------------***  INSERTITEM  ***----------------------------------*/
  58. /*    
  59. Insert an item at position <index>
  60. ----------------------------------------------------------------------------------------*/
  61.  
  62. void    ZArray::InsertItem(void* item, const long index)
  63. {
  64.     // insert the item into the array at position <index>. The value of <index> is one-based.
  65.     // This extends the array by one item.
  66.     
  67.     InsertElement( index - 1 );
  68.     SetArrayItem( item, index );
  69.     
  70.     SendMessage( msgArrayItemInserted, (void*) index );
  71. }
  72.  
  73.  
  74. /*--------------------------------***  APPENDITEM  ***----------------------------------*/
  75. /*    
  76. add an item at the end of the array
  77. ----------------------------------------------------------------------------------------*/
  78.  
  79. void    ZArray::AppendItem(void* item)
  80. {
  81.     // adds the item to the end of the array. This grows it by one item.
  82.     
  83.     InsertElement( numElements );
  84.     SetArrayItem( item, numElements );
  85.     
  86.     SendMessage( msgArrayItemAdded, (void*) numElements );
  87. }
  88.  
  89.  
  90. /*-------------------------------***  SETARRAYITEM  ***---------------------------------*/
  91. /*    
  92. replace an item at position <index>
  93. ----------------------------------------------------------------------------------------*/
  94.  
  95. void    ZArray::SetArrayItem(void* item, const long index)
  96. {
  97.     // sets the item into the array at <index>, which is one-based.
  98.     
  99.     ASSERT( "Index out of range; ZArray::SetArrayItem",  index >= 0 && index <= numElements, index )        
  100.     
  101.     BlockMoveData(item, (*a + (blkSize * (index - 1))), blkSize);
  102.     
  103.     SendMessage( msgArrayItemChanged, (void*) index );
  104. }
  105.  
  106.  
  107. /*-------------------------------***  GETARRAYITEM  ***---------------------------------*/
  108. /*    
  109. return the item at position <index> (returns a COPY)
  110. ----------------------------------------------------------------------------------------*/
  111.  
  112. void    ZArray::GetArrayItem(void* item, const long index)
  113. {
  114.     // gets the item at poition <index> in the array. Index is one-based.
  115.     
  116.     ASSERT( "Index out of range; ZArray::GetArrayItem",  index >= 0 && index <= numElements, index )        
  117.     
  118.     BlockMoveData((*a + (blkSize * (index - 1))), item, blkSize);
  119. }
  120.  
  121.  
  122. /*---------------------------***  CONCATENATEARRAY  ***---------------------------------*/
  123. /*    
  124. appends the array passed to the end of this one. This does not attempt to maintain sort
  125. order, etc- it just joins the arrays. The source array is unaffected and its data is
  126. copied. NOTE: The two arrays *MUST* have the same sized elements- you cannot concatenate
  127. arrays that contain incompatible data types.
  128. ----------------------------------------------------------------------------------------*/
  129.  
  130. void    ZArray::ConcatenateArray( ZArray* anArray )
  131. {
  132.     long    appendedItems;
  133.     long    physExtent;
  134.     
  135.     FailNILParam( anArray );
  136.     
  137.     // check element sizes are compatible:
  138.     
  139.     ASSERT( "Block sizes don't match; ZArray::ConcatentateArray", anArray->blkSize == blkSize, blkSize )
  140.     
  141.     // is there anything to copy?
  142.     
  143.     if (( appendedItems = anArray->CountItems()) > 0 )
  144.     {
  145.         // extend our handle to accommodate the additional stuff. Note that since we allocate
  146.         // in multiples of a physical block count, we need to take this into account when
  147.         // joining the arrays
  148.         
  149.         physExtent = appendedItems + numElements;
  150.         physExtent += kNumPhysicalBlockAlloc - ( physExtent % kNumPhysicalBlockAlloc );
  151.         
  152.         if ( physExtent > physicalBlks )
  153.         {
  154.             physicalBlks = physExtent;
  155.             
  156.             SetHandleSize( a, physicalBlks * blkSize );
  157.             FailMemError();
  158.         }
  159.         
  160.         Ptr p = *anArray->a;
  161.         Ptr    q = *a + ( numElements * blkSize );
  162.         
  163.         BlockMoveData( p, q, appendedItems * blkSize );
  164.         
  165.         numElements += appendedItems;
  166.     }
  167. }
  168.  
  169.  
  170. /*---------------------------------***  FINDINDEX  ***----------------------------------*/
  171. /*
  172. returns the index of an item in the array, or 0 if not found.    
  173. ----------------------------------------------------------------------------------------*/
  174.  
  175. long    ZArray::FindIndex(void* item)
  176. {
  177.     // performs a linear search and returns the index of the item, if found.
  178.     
  179.     if ( numElements < 1 )
  180.         return 0;
  181.         
  182.     long        i = 0;
  183.     Boolean        found = FALSE;
  184.     
  185.     do
  186.     {
  187.         if (EqualMem(*a + ( blkSize * i ), item, blkSize))
  188.         {
  189.             found = TRUE;
  190.             break;
  191.         }
  192.     }
  193.     while( i++ < numElements );
  194.  
  195.     return ( found? i + 1 : 0 );
  196. }
  197.  
  198. /*--------------------------------***  DELETEITEM  ***----------------------------------*/
  199. /*    
  200. Delete an item at position <index>
  201. ----------------------------------------------------------------------------------------*/
  202.  
  203. void    ZArray::DeleteItem( const long index )
  204. {
  205.     // deletes the item at position <index> (1-based). Items above are moved down one.
  206.     
  207.     DeleteElement( index - 1 );
  208.     
  209.     SendMessage( msgArrayItemDeleted, (void*) index );
  210. }
  211.  
  212.  
  213. /*---------------------------------***  DELETEALL  ***----------------------------------*/
  214. /*    
  215. deletes all items in the array
  216. ----------------------------------------------------------------------------------------*/
  217.  
  218. void    ZArray::DeleteAll()
  219. {
  220.     numElements = 0;
  221.     physicalBlks = kNumPhysicalBlockAlloc;
  222.     
  223.     SetHandleSize( a, blkSize * physicalBlks );
  224.     
  225.     SendMessage( msgArrayAllDeleted, NULL );
  226. }
  227.  
  228.  
  229. /*----------------------------------***  MOVEITEM  ***----------------------------------*/
  230. /*    
  231. move an item from one place in the array to another
  232. ----------------------------------------------------------------------------------------*/
  233.  
  234. void    ZArray::MoveItem( const long curIndex, const long newIndex )
  235. {
  236.     // moves the item at <curIndex> to position <newIndex> (all 1-based), moving other items
  237.     // as needed to keep things in order.
  238.     
  239.     ASSERT( "Bad index; ZArray::MoveItem", curIndex > 0 && curIndex <= numElements && newIndex > 0 && newIndex <= numElements, 0 )
  240.     
  241.     void* temp = (void*) NewPtr( blkSize );
  242.     
  243.     FailNIL(temp);
  244.     
  245.     // copy the item we want to move to a temporary space
  246.     
  247.     GetArrayItem( temp, curIndex);
  248.     
  249.     // delete its current position, which will move stuff as needed
  250.     
  251.     DeleteElement( curIndex - 1 );
  252.     
  253.     // insert it into the new position, which moves other stuff as needed
  254.     
  255.     InsertItem( temp, newIndex );
  256.     
  257.     // get rid of the temporary space
  258.     
  259.     DisposePtr((Ptr) temp);
  260.     SendMessage( msgArrayItemMoved, (void*) newIndex );
  261. }
  262.  
  263.  
  264. /*----------------------------------***  SWAPITEM  ***----------------------------------*/
  265. /*    
  266. Swap two items in the array
  267. ----------------------------------------------------------------------------------------*/
  268.  
  269. void    ZArray::Swap( const long itema, const long itemb )
  270. {
  271.     // swaps items a and b.
  272.     ASSERT( "Bad index; ZArray::Swap", itema > 0 && itema <= numElements && itemb > 0 && itemb <= numElements, 0 )
  273.     
  274.     // make some swap space
  275.     
  276.     void* tempa = (void*) NewPtr( blkSize );
  277.     void* tempb = (void*) NewPtr( blkSize );
  278.     FailNIL(tempa);
  279.     FailNIL(tempb);
  280.     
  281.     GetArrayItem( tempa, itema);
  282.     GetArrayItem( tempb, itemb);
  283.     SetArrayItem( tempa, itemb);
  284.     SetArrayItem( tempb, itema);
  285.     
  286.     DisposePtr((Ptr) tempa);
  287.     DisposePtr((Ptr) tempb);
  288.     
  289.     SendMessage( msgArrayItemMoved, (void*) itema );
  290. }
  291.  
  292.  
  293. /*---------------------------------***  COUNTITEMS  ***---------------------------------*/
  294. /*    
  295. return the number of items in the array
  296. ----------------------------------------------------------------------------------------*/
  297.  
  298. long    ZArray::CountItems()
  299. {
  300.     return numElements;
  301. }
  302.  
  303.  
  304. /*----------------------------------***  DOFOREACH  ***---------------------------------*/
  305. /*    
  306. for each item in the array, pass it to the grovelling proc passed
  307. ----------------------------------------------------------------------------------------*/
  308.  
  309. void    ZArray::DoForEach(IteratorProcPtr aProc, const long ref)
  310. {
  311.     if (aProc && (numElements > 0))
  312.     {
  313.         long    i = numElements;
  314.         void*    temp = (void*) NewPtr( blkSize );
  315.         
  316.         FailNIL( temp );
  317.         
  318.         while ( i )
  319.         {
  320.             GetArrayItem( temp, i);
  321.             (*aProc)(temp, ref);
  322.             
  323.             // in case the proc changed the item, set it back
  324.             
  325.             SetArrayItem( temp, i--);
  326.         }
  327.         
  328.         DisposePtr((Ptr) temp);
  329.     }
  330. }
  331.  
  332.  
  333. /*-------------------------------------***  SORT  ***-----------------------------------*/
  334. /*    
  335. sort the items in the array into order. The supplied comparison function allows you to
  336. sort anything based on any ordering criteria. Uses a very fast shellsort algorithm. Your
  337. sort function needs to examine the relevant criteria in the items passed, and decide what
  338. order they come in. It should return -1 if a < b, +1 if a > b, and 0 if equal. <ref> can be
  339. anything you want- it is simply passed to the compare function. It might be another object
  340. for example (hint, hint!).
  341.  
  342. ----------------------------------------------------------------------------------------*/
  343.  
  344. void    ZArray::Sort( register SortCmpProcPtr compareProc, register const long ref )
  345. {
  346.     register long    E,N,M,J,K,R;
  347.     register short    cp;
  348.     
  349.     register void*    itema;
  350.     register void*    itemb;
  351.     
  352.     // sanity check- there IS a sort function, right?
  353.     
  354.     FailOSErr((compareProc == NULL)? kUndefinedCompProcErr : noErr );
  355.     
  356.     // allocate some temporary storage
  357.     
  358.     FailNIL(itema = (void*) NewPtr( blkSize ));
  359.     FailNIL(itemb = (void*) NewPtr( blkSize ));
  360.     
  361.     // initialise the control variables to the number of elements in the list
  362.     
  363.     M = E = N = numElements;
  364.     N++;
  365.     
  366.     // and... sort!
  367.     
  368.     do
  369.     {
  370.         M /= 2;
  371.         if (M <= 0)
  372.             break;
  373.             
  374.         K = E - M;
  375.         J = 1;
  376.         
  377.         do
  378.         {
  379.             N = J;
  380.             do
  381.             {
  382.                 R = N + M;
  383.                 GetArrayItem( itema, N );                        // get first item
  384.                 GetArrayItem( itemb, R );                        // get second item
  385.                 
  386.                 cp = (*compareProc)( itema, itemb, ref );        // call the comparison function
  387.                 
  388.                 if ( cp < 1 )                                    // no need to swap (a <= b)
  389.                     break;
  390.                     
  391.                 Swap( N, R );                                    // swap items in the array
  392.                     
  393.                 N -= M;
  394.             }
  395.             while ( N > 0 );
  396.             J++;
  397.         }
  398.         while (J <= K);
  399.     }
  400.     while( M > 0 );
  401.     
  402.     // all done, now release the temporary storage
  403.     
  404.     DisposePtr((Ptr) itema);
  405.     DisposePtr((Ptr) itemb);
  406. }
  407.  
  408. /*-------------------------------------***  SORT  ***-----------------------------------*/
  409. /*    
  410. simpler interface to Sort- indirectly calls the Compare method, which you can override.
  411.  
  412. ----------------------------------------------------------------------------------------*/
  413.  
  414. void    ZArray::Sort()
  415. {
  416.     Sort( vCompareFunc, (long) this );
  417. }
  418.  
  419. /*------------------------------------***  QSORT  ***-----------------------------------*/
  420. /*    
  421. sorts using qsort in std C lib, which can take from 1/4 to 1/2 the time as Sort. Note
  422. though that you cannot pass a <ref>, so you compare proc must NOT rely on it for any
  423. purpose if using QSort instead of Sort.
  424. ----------------------------------------------------------------------------------------*/
  425.  
  426. void    ZArray::QSort( SortCmpProcPtr compareProc )
  427. {
  428.     char    hs = HGetState( a );
  429.     
  430.     HLock( a );    
  431.     
  432.     qsort( *a, numElements, blkSize, ( int(*)( const void*, const void* )) compareProc );
  433.     
  434.     HSetState( a, hs );
  435. }
  436.  
  437. /*----------------------------------***  COMPARE  ***-----------------------------------*/
  438. /*
  439. compare two items and return their relative ordering: -1 if a < b, +1 if a > b, 0 if a == b.
  440. You need to override this if you wish to use the simple call to Sort() above.    
  441. ----------------------------------------------------------------------------------------*/
  442.  
  443. short    ZArray::Compare( void* itema, void* itemb, const long ref )
  444. {
  445.     return 0;
  446. }
  447.  
  448. /*------------------------------***  INSERTSORTEDITEM  ***------------------------------*/
  449. /*
  450. insert the item into the list at the correct place assuming the list is sorted. This
  451. does a binary search to locate the position, based on the comparison function provided.
  452. Normally the comparison function is the same one you'd use with sort, so everything
  453. agrees. Returns the index position it was inserted at.
  454. ----------------------------------------------------------------------------------------*/
  455.  
  456. long    ZArray::InsertSortedItem( void* item, SortCmpProcPtr compareProc, const long ref )
  457. {
  458.     FailNILParam( compareProc );
  459.     
  460.     short    rel;
  461.     long    pos = BFindIndex( item, compareProc, ref );
  462.     void*    itemB;
  463.     
  464.     // <pos> represents the NEAREST item, but we don't know if we need to insert
  465.     // before or after this item, so we need to do one more compare
  466.     
  467.     if ( pos > 0 )
  468.     {
  469.         FailNIL( itemB = (void*) NewPtr( blkSize ));
  470.         
  471.         GetArrayItem( itemB, pos );
  472.         
  473.         rel = (*compareProc)( item, itemB, ref );
  474.         
  475.         DisposePtr((Ptr) itemB );
  476.         
  477.         if ( rel > 0 )
  478.             pos++;
  479.     }    
  480.     
  481.     if (( pos > numElements ) || ( pos == 0 ))
  482.     {
  483.         AppendItem( item );
  484.         pos = numElements;
  485.     }
  486.     else
  487.         InsertItem( item, pos );
  488.         
  489.     return pos;
  490. }
  491.  
  492. /*------------------------------***  INSERTSORTEDITEM  ***------------------------------*/
  493. /*
  494. insert the item into the list at the correct place assuming the list is sorted. This uses
  495. the built in compare function which calls the Compare method.
  496. ----------------------------------------------------------------------------------------*/
  497.  
  498. long    ZArray::InsertSortedItem( void* item, const long ref )
  499. {
  500.     return InsertSortedItem( item, vCompareFunc, ref );
  501. }
  502.  
  503.  
  504. /*-----------------------------***  Protected Members  ***------------------------------*/
  505.  
  506.  
  507. /*-------------------------------***  INSERTELEMENT  ***--------------------------------*/
  508. /*    
  509. make space for one element in the handle
  510. ----------------------------------------------------------------------------------------*/
  511.  
  512. void    ZArray::InsertElement( const long index )
  513. {
  514.     // grow the handle by one element, moving items above <index> up one. This also
  515.     // sets the numElements data member. Index is zero-based.
  516.     
  517.     long    newSize;
  518.     
  519.     // check that the index parameter is sensible
  520.     
  521.     ASSERT( "Index out of range; ZArray::InsertElement",  index >= 0 && index <= numElements, index )
  522.     
  523.     // grow the handle if the number of physical blocks is insufficient
  524.     
  525.     newSize = ( numElements + 1 ) * blkSize;
  526.     
  527.     if ( newSize > ( physicalBlks * blkSize ))
  528.     {
  529.         physicalBlks += kNumPhysicalBlockAlloc;
  530.         
  531.         SetHandleSize( a, physicalBlks * blkSize );
  532.         FailOSErr(MemError());
  533.     }
  534.     
  535.     // OK, the handle is now larger by one element- do we need to move any data around?
  536.     
  537.     if (index < numElements)
  538.     {
  539.         // yes, subsequent entries move up by <blkSize> bytes
  540.         
  541.         HLock( a );
  542.         BlockMoveData(    *a + (blkSize * index),
  543.                         *a + (blkSize * (index + 1)),
  544.                         blkSize * (numElements - index));
  545.         HUnlock( a );
  546.     }
  547.     
  548.     // increment the count of elements
  549.     
  550.     numElements++;
  551. }
  552.  
  553. /*-------------------------------***  DELETEELEMENT  ***--------------------------------*/
  554. /*    
  555. remove space for one element in the handle
  556. ----------------------------------------------------------------------------------------*/
  557.  
  558. void    ZArray::DeleteElement( const long index )
  559. {
  560.     // shrink the handle by one element, after moving entries above <index> down by one.
  561.     // <index> is zero-based.
  562.     
  563.     // check that the index parameter is sensible
  564.     
  565.     ASSERT( "Index out of range; ZArray::DeleteElement",  index >= 0 && index < numElements, index )        
  566.     
  567.     // one less element
  568.     
  569.     numElements--;
  570.         
  571.     // if the index is not the last item, move everything down to fill the space
  572.     
  573.     if (index < numElements)
  574.     {
  575.         HLock( a );
  576.         BlockMoveData(    *a + (blkSize * (index + 1)),
  577.                         *a + (blkSize * index),
  578.                         blkSize * (numElements - index + 1));
  579.         HUnlock( a );
  580.     }
  581.     
  582.     // shrink the handle if we can remove a whole multiple of physical blocks
  583.     
  584.     if (( physicalBlks - numElements ) > kNumPhysicalBlockAlloc )
  585.     {
  586.         physicalBlks = MAX( 0, physicalBlks - kNumPhysicalBlockAlloc );
  587.         SetHandleSize( a, blkSize * physicalBlks );
  588.     }
  589. }
  590.  
  591.  
  592. /*---------------------------------***  BFINDINDEX  ***---------------------------------*/
  593. /*    
  594. use the compare function to determine where the item SHOULD be inserted (binary search)
  595. ----------------------------------------------------------------------------------------*/
  596.  
  597. long    ZArray::BFindIndex( void* item, SortCmpProcPtr compareProc, const long ref )
  598. {
  599.     unsigned long    lowItem, highItem, midItem, pos = 1;
  600.     short            compare;
  601.     void*            itemB;
  602.     
  603.     FailNILParam( compareProc );
  604.     
  605.     lowItem = 1;
  606.     highItem = numElements;
  607.     
  608.     // if the list is empty, we return item 1, since we can simply append the item.
  609.     
  610.     if ( numElements < 1 )
  611.         pos = 0;
  612.     else
  613.     {
  614.         // make space for the item we are going to compare
  615.         
  616.         FailNIL( itemB = (void*) NewPtr( blkSize ));
  617.         
  618.         while ( lowItem <= highItem )
  619.         {
  620.             midItem = ( highItem + lowItem ) >> 1;
  621.             
  622.             GetArrayItem( itemB, midItem );
  623.             
  624.             // compare this item to the one we are looking for
  625.             
  626.             compare = (*compareProc)( item, itemB, ref );
  627.             
  628.             // if an exact match, then insert right here
  629.             
  630.             if ( compare == 0 )
  631.                 break;
  632.                 
  633.             // otherwise search half the list
  634.             
  635.             if ( compare > 0 )
  636.                 lowItem = midItem + 1;
  637.             else
  638.                 highItem = midItem - 1;
  639.         }
  640.         
  641.         DisposePtr((Ptr) itemB );
  642.         pos = MAX( midItem, 1 );
  643.     }
  644.     
  645.     return pos;
  646. }
  647.  
  648.  
  649. /*------------------------------***  READFROMSTREAM  ***--------------------------------*/
  650. /*    
  651. rebuild/initialise array from stream. This overwrites/removes any existing contents.
  652. ----------------------------------------------------------------------------------------*/
  653.  
  654. void    ZArray::ReadFromStream( ZStream* aStream )
  655. {
  656. #if _MACZOOP_STREAMS
  657.     ZComrade::ReadFromStream( aStream );
  658.     
  659.     // read array data items from the stream. First item is block size, then count.
  660.     
  661.     aStream->ReadLong( &blkSize );
  662.     aStream->ReadLong( &numElements );
  663.     
  664.     // if num elements is not 0, read data into array's storage handle
  665.     
  666.     if ( numElements > 0 )
  667.     {
  668.         if ( a )
  669.             DisposeHandle( a );
  670.         
  671.         aStream->ReadHandle( &a );
  672.         
  673.         // the number of phyical blocks needs to be adjusted to this size.
  674.         // We do not bother rounding this up to a whole multiple of
  675.         // the physical block count- it'll work anyway.
  676.         
  677.         physicalBlks = GetHandleSize( a ) / blkSize;
  678.     }
  679. #endif
  680. }
  681.  
  682.  
  683. /*-------------------------------***  WRITETOSTREAM  ***--------------------------------*/
  684. /*    
  685. write entire array object to stream
  686. ----------------------------------------------------------------------------------------*/
  687.  
  688. void    ZArray::WriteToStream( ZStream* aStream )
  689. {
  690. #if _MACZOOP_STREAMS
  691.     ZComrade::WriteToStream( aStream );
  692.     
  693.     // write all the array items to the stream.
  694.     
  695.     long    i, numItems;
  696.     void*    temp;
  697.     
  698.     numItems = CountItems();
  699.     
  700.     // first two items in stream are block size and item count
  701.     
  702.     aStream->WriteLong( blkSize );
  703.     aStream->WriteLong( numItems );
  704.     
  705.     // ...followed by the data:
  706.     
  707.     if ( numItems > 0 )
  708.         aStream->WriteHandle( a );
  709. #endif
  710. }
  711.  
  712.  
  713.  
  714. #pragma mark -
  715. /*--------------------------------***  vCompareFunc  ***--------------------------------*/
  716.  
  717. static short    vCompareFunc( void* a, void* b, const long ref)
  718. {
  719.     ZArray*        theArray = (ZArray*) ref;
  720.     
  721.     if ( theArray )
  722.         return theArray->Compare( a, b, ref );    
  723.     else
  724.         return 0;
  725. }
  726.  
  727.  
  728.